/**
 * 
 */
package info.niwota.frames;

import info.niwota.commons.io.Files;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;

import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.ImageColumns;
import android.view.Display;
import android.view.WindowManager;

/**
 * @author qiangli
 * 
 */
public final class BackgroundImages {

	public static final int BG_SELECT_DEFAULT = R.drawable.bg_bluishsky;
	private static final int BUFSIZE = 1024;

	/**
	 * 
	 */
	private BackgroundImages() {
		//
	}

	public static String getRandomImage(Context context) {
		String[] proj = new String[] { ImageColumns.DATA };
		Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
		Cursor c = null;
		c = context.getContentResolver().query(uri, proj, null, null, null);
		if (!c.moveToFirst()) {
			return null;
		}
		int cnt = c.getCount();
		if (cnt == 0) {
			return null; // no immage?
		}
		Random rand = new Random();
		int pos = rand.nextInt(cnt);
		String p = null;
		try {
			if (c.moveToPosition(pos)) {
				p = c.getString(0);
			}
		} finally {
			c.close();
		}
		return p;
	}

	public static void thumbnail(InputStream in, OutputStream out, int width,
			int height) {
		Bitmap image = BitmapFactory.decodeStream(in);
		
		int w = image.getWidth();
		int h = image.getHeight();
		float scalew = ((float) width) / w;
		float scaleh = ((float) height) / h;
		float scale = Math.min(scalew, scaleh);
		Matrix matrix = new Matrix();
		matrix.postScale(scale, scale);
		
		Bitmap resized = Bitmap.createBitmap(image, 0, 0, w, h, matrix, true);
		resized.compress(Bitmap.CompressFormat.JPEG, 75, out);
		//
		image.recycle();
		resized.recycle();
	}
	
	static void transform(InputStream in, OutputStream out, int width,
			int height) {
		Bitmap image = BitmapFactory.decodeStream(in);
		Bitmap resized = transform(image, width, height, false);
		resized.compress(Bitmap.CompressFormat.JPEG, 75, out);
		//
		image.recycle();
		resized.recycle();
	}

	/**
	 * Load image scaled if too big with hint of size 200x200
	 * 
	 * @param ctx
	 * @param f
	 * @return
	 */
	public static Drawable loadImage(Context ctx, File f) {
		// 320x240
		WindowManager wm = (WindowManager) ctx
				.getSystemService(Context.WINDOW_SERVICE);
		Display d = wm.getDefaultDisplay();
		final int width = d.getWidth();
		final int height = d.getHeight();
		//
		String path = f.getPath();
		Options opt = new Options();
		opt.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, opt);
		int w = opt.outWidth;
		int h = opt.outHeight;
		//
		float scalew = w / width;
		float scaleh = h / height;
		int scale = (int) Math.max(scalew, scaleh);
		//
		opt.inJustDecodeBounds = false;
		opt.inSampleSize = scale;
		Bitmap bm = BitmapFactory.decodeFile(path, opt);
		return new BitmapDrawable(bm);
	}

	public static File loadBG(Context ctx) throws Exception {
		int sel = Preferences.getBackgroundSelection(ctx,
				Preferences.BG_SELECT_SAMPLE_ANDROID);
		boolean gonewild = false;
		if (sel == Preferences.BG_SELECT_GONE_WILD) {
			Random rand = new Random();
			// gone wild is the last selection
			sel = rand.nextInt(Preferences.BG_SELECT_GONE_WILD * 2);
			sel = (sel < Preferences.BG_SELECT_GONE_WILD ? sel
					: Preferences.BG_SELECT_PICK);
			gonewild = true;
		}
		switch (sel) {
		case Preferences.BG_SELECT_WALLPAPER: {
			Drawable d = ctx.getWallpaper();
			return save(ctx, d, sel + ".jpg");
		}
		case Preferences.BG_SELECT_PICK: {
			String p = (gonewild ? getRandomImage(ctx) : Preferences
					.getBackgroundImagePath(ctx, null));
			;
			return new File(p);
		}
		default:
			int resid = Preferences.getBackgroundSelectedResource(sel,
					BG_SELECT_DEFAULT);
			InputStream is = ctx.getResources().openRawResource(resid);
			return save(ctx, is, sel + ".jpg");
		}
	}

	private static File save(Context ctx, InputStream is, String name)
			throws IOException {
		File file = getFile(ctx, name);
		try {
			FileOutputStream os = new FileOutputStream(file);
			copy(is, os);
			os.close();
		} catch (Exception e) {
			//
		} finally {
			is.close();
		}
		return file;
	}

	private static File getFile(Context ctx, String name) {
		File dir = Files.getSubDir(ctx, "bg");
		if (!dir.exists()) {
			dir.mkdirs();
		}
		File file = new File(dir, name);
		return file;
	}

	private static File save(Context ctx, Drawable image, String name)
			throws IOException {
		CompressFormat cf = CompressFormat.JPEG;
		File file = getFile(ctx, name);

		save(ctx, file, image, 100, cf);

		return file;
	}

	private static void save(Context ctx, File file, Drawable image, int alpha,
			CompressFormat cf) throws IOException {
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file);
			Bitmap bitmap = null;
			if (image instanceof BitmapDrawable) {
				bitmap = ((BitmapDrawable) image).getBitmap();
			} else {
				final Config bc = Bitmap.Config.ARGB_8888;
				final int w = image.getIntrinsicWidth();
				final int h = image.getIntrinsicHeight();
				bitmap = Bitmap.createBitmap(w, h, bc);
				Canvas c = new Canvas(bitmap);
				c.drawColor(Color.WHITE);
				image.setBounds(0, 0, w, h);
				image.setAlpha(alpha);
				image.setDither(true);
				image.draw(c);
			}
			//
			final int q = 100;
			bitmap.compress(cf, q, fos);
		} finally {
			if (fos != null) {
				fos.close();
			}
		}
	}

	private static void copy(InputStream is, OutputStream os)
			throws IOException {
		byte[] buf = new byte[BUFSIZE];
		while (true) {
			int read = is.read(buf);
			if (read == -1) {
				break;
			}
			if (read > 0) {
				os.write(buf, 0, read);
			}
		}
		os.flush();
	}

	private static Bitmap transform(Bitmap source, int targetWidth,
			int targetHeight, boolean scaleUp) {
		Matrix scaler = new Matrix();
		//
		int deltaX = source.getWidth() - targetWidth;
		int deltaY = source.getHeight() - targetHeight;
		if (!scaleUp && (deltaX < 0 || deltaY < 0)) {
			/*
			 * In this case the bitmap is smaller, at least in one dimension,
			 * than the target. Transform it by placing as much of the image as
			 * possible into the target and leaving the top/bottom or left/right
			 * (or both) black.
			 */
			Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,
					Bitmap.Config.ARGB_8888);
			Canvas c = new Canvas(b2);

			int deltaXHalf = Math.max(0, deltaX / 2);
			int deltaYHalf = Math.max(0, deltaY / 2);
			Rect src = new Rect(deltaXHalf, deltaYHalf, deltaXHalf
					+ Math.min(targetWidth, source.getWidth()), deltaYHalf
					+ Math.min(targetHeight, source.getHeight()));
			int dstX = (targetWidth - src.width()) / 2;
			int dstY = (targetHeight - src.height()) / 2;
			Rect dst = new Rect(dstX, dstY, targetWidth - dstX, targetHeight
					- dstY);
			c.drawBitmap(source, src, dst, null);
			return b2;
		}
		
		float bitmapWidthF = source.getWidth();
		float bitmapHeightF = source.getHeight();

		float bitmapAspect = bitmapWidthF / bitmapHeightF;
		float viewAspect = (float) targetWidth / targetHeight;

		if (bitmapAspect > viewAspect) {
			float scale = targetHeight / bitmapHeightF;
			if (scale < .9F || scale > 1F) {
				scaler.setScale(scale, scale);
			} else {
				scaler = null;
			}
		} else {
			float scale = targetWidth / bitmapWidthF;
			if (scale < .9F || scale > 1F) {
				scaler.setScale(scale, scale);
			} else {
				scaler = null;
			}
		}

		Bitmap b1;
		if (scaler != null) {
			// this is used for minithumb and crop, so we want to filter here.
			b1 = Bitmap.createBitmap(source, 0, 0, source.getWidth(),
					source.getHeight(), scaler, true);
		} else {
			b1 = source;
		}

		int dx1 = Math.max(0, b1.getWidth() - targetWidth);
		int dy1 = Math.max(0, b1.getHeight() - targetHeight);

		Bitmap b2 = Bitmap.createBitmap(b1, dx1 / 2, dy1 / 2, targetWidth,
				targetHeight);
		return b2;
	}
}
